package top.xiaoazi.futureletterserver.module.user.controller;

import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import top.xiaoazi.futureletterserver.common.AppVariable;
import top.xiaoazi.futureletterserver.common.FileStoreVariable;
import top.xiaoazi.futureletterserver.module.user.dto.ResetPasswordDTO;
import top.xiaoazi.futureletterserver.module.user.service.UserService;
import top.xiaoazi.futureletterserver.module.user.entity.User;
import top.xiaoazi.futureletterserver.common.R;
import top.xiaoazi.futureletterserver.module.user.vo.UserLoginRequestVO;
import top.xiaoazi.futureletterserver.module.user.vo.UserRedisVO;
import top.xiaoazi.futureletterserver.module.verifycode.entity.VerifyCode;
import top.xiaoazi.futureletterserver.module.verifycode.service.VerifyCodeService;
import top.xiaoazi.futureletterserver.utils.*;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {

    private final String PREV_PATH = "/api/image/" + FileStoreVariable.IMAGE_USER_PROFILE_PHOTO + "/";
    private final String SAVE_PATH = FileStoreVariable.BASE_PATH + FileStoreVariable.IMAGE_USER_PROFILE_PHOTO;


    @Autowired
    private UserService userService;

    @Autowired
    private UserUtils userUtils;

    @Autowired
    private RequestUtils requestUtils;

    @Autowired
    private VerifyCodeService verifyCodeService;

    @Autowired
    private EmailUtils emailUtils;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private JwtUtils jwtUtils;

    /**
     * 用户登录接口
     * 使用 jwt 验证
     *
     * @return token 和 用户数据
     */
    @PostMapping("/login")
    public R login(@RequestBody UserLoginRequestVO userLoginRequestVO, HttpServletRequest request) {

        // 1. 先判断验证码是否正确，再去判断账号或密码是否正确
        HashMap<String, Object> map = new HashMap<>();
        // 判断验证码是否正确
        VerifyCode verifyCode = verifyCodeService.getById(userLoginRequestVO.getCaptchaId());
        if (!userLoginRequestVO.getCaptcha().toLowerCase().equals(verifyCode.getResult())) {
            return R.success(201, "验证码错误!");
        }

        User user = new User(userLoginRequestVO);
        User resultUser = userService.isOk(user);
        if (resultUser == null || resultUser.getUserId() == null) {
            return R.success(201, "账号或密码错误!");
        }

        // 2. 密码正确判断Redis是否存在，如果存在删除缓存
        // 3. 使用 jwt 工具创建 token 令牌
        // 4. 将 token 保存至 redis 中 - redis key: token，value: User
        // 5. 登录成功后将 user 和 token 都返回给前端
        map = userService.login(resultUser, request);
        return R.success("登录成功", map);

    }

    @GetMapping("/is-login")
    public R isLogin(HttpServletRequest request) {
        String token = request.getHeader(AppVariable.HEADER_TOKEN);
        // 判断 redis 是否存在 token
        // redis 存在 token 再去判断当前 token 是否过期
        if (token == null || !redisUtils.hasKey(token)) {
            return R.success("未登录", false);
        }
        // 走到这表示存在 token 的 key，判断该 token 是否过期
        if (!jwtUtils.validateToken(token)) {
            return R.success("未登录", false);
        }
        UserRedisVO userRedisVO = (UserRedisVO) redisUtils.get(token);
        // 判断该用户是否修改密码，也就是 redis 中的 密码是否相同
        User user = userService.getByUserId(userRedisVO.getUserId());
        if (!user.getPassword().equals(userRedisVO.getPassword())) {
            // 修改密码了，这个 token 无效了
            redisUtils.delete(token);
            return R.success("未登录", false);
        }
        return R.success("已登录", true);
    }

    /**
     * 退出登录
     *
     * @param request
     * @return
     */
    @PostMapping("/exit")
    public R exit(HttpServletRequest request) {
        userService.exit(request);
        return R.success("退出成功");
    }

    /**
     * 管理员级别注册用户
     *
     * @param user
     * @return
     */
    @PostMapping("/sys/reg")
    public R systemReg(@RequestBody User user) {
        if (user.getUsername() == null || user.getPassword() == null || user.getUsername().equals("") || user.getPassword().equals("")) {
            return R.success(requestUtils.BAD_REQUEST_STATE, requestUtils.BAD_REQUEST_MESSAGE);
        }
        User u = userService.getByUsername(user);
        if (u != null && u.getUsername() != null) {
            return R.success(requestUtils.USER_EXISTS_STATE, requestUtils.USER_EXISTS_MESSAGE);
        }

        userService.systemReg(user);
        return R.success("注册成功");
    }

//    @PostMapping("/test/reg")
//    public R systemReg(@RequestBody User user) {
//        if (user.getUsername() == null || user.getPassword() == null || user.getUsername().equals("") || user.getPassword().equals("")) {
//            return R.success(requestUtils.BAD_REQUEST_STATE, requestUtils.BAD_REQUEST_MESSAGE);
//        }
//        User u = userService.getByUsername(user);
//        if (u != null && u.getUsername() != null) {
//            return R.success(requestUtils.USER_EXISTS_STATE, requestUtils.USER_EXISTS_MESSAGE);
//        }
//
//        userService.systemReg(user);
//        return R.success("注册成功");
//    }

    /**
     * 用户注册
     *
     * @param data
     * @return
     */
    @PostMapping("/reg")
    public R reg(@RequestBody Map<String, String> data) {
        String username = data.get("username");
        String password = data.get("password");
        String email = data.get("email");
        String emailCode = data.get("emailCode");

        // 判断邮箱验证码是否正确
        if (!redisUtils.hasKey(email)) {
            return R.success(requestUtils.AUTH_CODE_PASS_STATE, requestUtils.AUTH_CODE_PASS_MESSAGE);
        }
        if (!redisUtils.get(email).equals(emailCode)) {
            return R.success(requestUtils.AUTH_CODE_ERROR_STATE, requestUtils.AUTH_CODE_ERROR_MESSAGE);
        }

        // 判断用户名密码是否合法
        if (username == null || password == null || username.equals("") || password.equals("")) {
            return R.success(requestUtils.BAD_REQUEST_STATE, requestUtils.BAD_REQUEST_MESSAGE);
        }

        // 判断是否是非法请求
        if (username.length() < 9 || password.length() < 10) {
            return R.success(requestUtils.BAD_REQUEST_STATE, requestUtils.BAD_REQUEST_MESSAGE);
        }

        User user = new User();
        user.setUsername(username);
        // 判断当前账号是否存在
        User u = userService.getByUsername(user);
        if (u != null && u.getUsername() != null) {
            return R.success(requestUtils.USER_EXISTS_STATE, requestUtils.USER_EXISTS_MESSAGE);
        }

        // 注册账号
        user.setPassword(password);
        user.setEmail(email);
        user.setCreateTime(TimeUtils.getTimeString());
        userService.reg(user);
        return R.success("注册成功");
    }

    /**
     * 生成邮箱验证码
     *
     * @return
     */
    @GetMapping("/generate-email-code")
    public R generateEmailCode(String email) {
        if (email == null || email.equals("") || !emailUtils.isValidEmail(email)) {
            return R.success(requestUtils.BAD_REQUEST_STATE, requestUtils.BAD_REQUEST_MESSAGE);
        }
        // 判断该邮箱是否被注册
        User user = userService.isExistEmail(email);
        if (user != null && user.getEmail() != null) {
            return R.success(requestUtils.EMAIL_EXISTS_STATE, requestUtils.EMAIL_EXISTS_MESSAGE);
        }
        // 判断是否存在验证码
        if (redisUtils.hasKey(email)) {
            return R.success(requestUtils.BAD_REQUEST_STATE, "验证码已发送, 请注意查看哦!");
        }
        User resultUser = new User();
        resultUser.setEmail(email);
        userService.generateEmailCode(resultUser);
        return R.success("已发送验证码至" + email + "，请注意查收。");
    }

    /**
     * 管理员专用接口，获取用户数据
     *
     * @return
     */
    @GetMapping("/sys/userinfo")
    public R sysUserinfo(@RequestParam(value = "pagesize") Integer pageSize, @RequestParam(value = "pagenum") Integer pageNumber, @RequestParam(value = "username") String username, HttpServletRequest request) {
        // 1. 校验参数是否正确
        if (pageSize == null || pageSize <= 1) {
            return R.success(requestUtils.BAD_REQUEST_STATE, requestUtils.BAD_REQUEST_MESSAGE);
        }
        if (pageNumber == null || pageNumber < 1) {
            return R.success(requestUtils.BAD_REQUEST_STATE, requestUtils.BAD_REQUEST_MESSAGE);
        }
        // 2. 算出偏移量
        int offset = (pageNumber - 1) * pageSize; // 假设 pageSize 为5，第一页偏移量为0，第二页偏移量为5，第三页偏移量为 10
        List<User> list = userService.getAllUser(pageSize, username, offset);
        Integer totalCount = userService.getAllCount(username);
        Map<String, Object> map = new HashMap<>();
        map.put("list", list);
        map.put("totalCount", totalCount);
        return R.success(map);
    }

    @PostMapping("/sys/update")
    public R sysUpdate(@RequestBody User user) {
        if (user.getUserId() == null || user.getUserId() <= 0) {
            return R.success(requestUtils.BAD_REQUEST_STATE, requestUtils.BAD_REQUEST_MESSAGE);
        }
        userService.sysUpdate(user);
        return R.success("修改成功");
    }

    /**
     * 获取当前登录的用户信息, 不走 redis
     *
     * @return
     */
    @GetMapping("/userinfo")
    public R getUserinfo(HttpServletRequest request) {
        Integer userId = userUtils.getUserId(request);
        User user = userService.getByUserId(userId);
        return R.success(new UserRedisVO(user));
    }

    /**
     * 判断用户是否有csdn脚本权限
     *
     * @param request
     * @return
     */
    @GetMapping("/is-csdn-script")
    public R isCsdnScript(HttpServletRequest request) {
        String token = request.getHeader(AppVariable.HEADER_TOKEN);
        User user = userService.isCsdnScript(token);
        if (user.getCSDNScriptState() == 1) {
            return R.success(true);
        } else {
            return R.success(false);
        }
    }

    /**
     * 获取当前cookie
     *
     * @param request
     * @return
     */
    @GetMapping("/get-csdn-cookie")
    public R getCsdnCookie(HttpServletRequest request) {
        return R.success("ok", userService.getCsdnCookie(userUtils.getUser(request)));
    }

    /**
     * 设置当前用户的 cookie
     *
     * @param data
     * @param request
     * @return
     */
    @PostMapping("/set-csdn-cookie")
    public R setCsdnCookie(@RequestBody Map<String, String> data, HttpServletRequest request) {
        userService.setCsdnCookie(data.get("cookie"), userUtils.getUserId(request));
        return R.success("修改成功");
    }

    /**
     * 获取登录用户的 csdn cookie 的状态
     *
     * @param request
     * @return
     */
    @GetMapping("/get-csdn-cookie-state")
    public R getCsdnCookieState(HttpServletRequest request) {
        return R.success(userService.getCsdnCookieState(userUtils.getUserId(request)));
    }

    /**
     * 设置他人回复自己评论区
     *
     * @param user
     * @param request
     * @return
     */
    @PostMapping("/set-other-comment-to-me")
    public R setOtherCommentToMe(@RequestBody User user, HttpServletRequest request) {
        if (user.getOtherCommentToMe().equals("")) {
            return R.success(requestUtils.BAD_REQUEST_STATE, requestUtils.BAD_REQUEST_MESSAGE);
        }
        user.setUserId(userUtils.getUserId(request));
        userService.setOtherCommentToMe(user);
        return R.success("保存成功");
    }

    /**
     * 设置他人回复自己评论区
     *
     * @param user
     * @param request
     * @return
     */
    @PostMapping("/set-reply-comment-to-other")
    public R setReplyCommentToOther(@RequestBody User user, HttpServletRequest request) {
        if (user.getReplyCommentToOther().equals("")) {
            return R.success(requestUtils.BAD_REQUEST_STATE, requestUtils.BAD_REQUEST_MESSAGE);
        }
        user.setUserId(userUtils.getUserId(request));
        userService.setReplyCommentToOther(user);
        return R.success("保存成功");
    }

    /**
     * 获取他人评论我的内容
     *
     * @param request
     * @return
     */
    @GetMapping("/get-other-comment-to-me")
    public R getOtherCommentToMe(HttpServletRequest request) {
        Integer userId = userUtils.getUserId(request);
        return R.success("ok", userService.getOtherCommentToMe(userId));
    }

    /**
     * 获取回复评论区的内容
     *
     * @param request
     * @return
     */
    @GetMapping("/get-reply-comment-to-other")
    public R getReplyCommentToOther(HttpServletRequest request) {
        Integer userId = userUtils.getUserId(request);
        return R.success("ok", userService.getReplyCommentToOther(userId));
    }

    @PostMapping("/modify-user-img")
    public R modifyUserImg(@RequestParam(value = "userImg", required = true) MultipartFile userImg, HttpServletRequest request) throws IOException {
        Integer userId = userUtils.getUserId(request);
        if (userId == null || userId <= 0) {
            return R.success(requestUtils.BAD_REQUEST_STATE, requestUtils.BAD_REQUEST_MESSAGE);
        }
        User user = userService.getByUserId(userId);
        if (user.getUserImg() == null || user.getUserImg().equals("")) {
            // 增加操作， 不用删除之前头像，直接新增头像即可。
            String imgName = FileUtils.save(userImg, SAVE_PATH);
            user.setUserImg(PREV_PATH + imgName);
        } else {
            // 修改操作， 先删除掉原来的照片头像
            FileUtils.delete(SAVE_PATH, FileUtils.getFileNameByUrl(user.getUserImg()));
            // 新增当前的照片
            String imgName = FileUtils.save(userImg, SAVE_PATH);
            user.setUserImg(PREV_PATH + imgName);
        }
        // 保存当前的新照片
        userService.setUserImg(user);
        return R.success("修改成功");
    }

    @PostMapping("/modify-userinfo")
    public R modifyUserinfo(@RequestBody User user) {
        if (user.getUserId() == null || user.getUserId() <= 0) {
            return R.success(requestUtils.BAD_REQUEST_STATE, requestUtils.BAD_REQUEST_MESSAGE);
        }
        userService.modifyUserinfo(user);
        return R.success("修改成功");
    }

    @GetMapping("/test")
    public R test() {
//        boolean b = emailUtils.sendHtmlEmail("验证码", emailUtils.getDefaultEmailTemplate("验证码为: 2023, 有效期为2分钟."), "623847465@qq.com");
//        return R.success(b);
        System.out.println(FileStoreVariable.BASE_PATH);
        return R.success(FileStoreVariable.BASE_PATH);
    }


    /**
     * 重置密码接口，获取用户通过username
     *
     * @return
     */
    @GetMapping("/rest/get-by-username")
    public R restGetByUsername(String username) {
        if (username == null || username.equals("")) {
            return R.success(requestUtils.BAD_REQUEST_STATE, requestUtils.BAD_REQUEST_MESSAGE);
        }
        User resultUser = userService.getByUsername(username);
        if (resultUser == null || resultUser.getUserId() == null) {
            return R.success(new UserRedisVO());
        }

        UserRedisVO userRedisVO = new UserRedisVO();
        userRedisVO.setUsername(username);
        userRedisVO.setUserId(resultUser.getUserId());
        // 开通权限, 允许用户设置密码
        redisUtils.set(RedisKeyUtils.getRestPasswordKey(username), new UserRedisVO(resultUser), 30, TimeUnit.MINUTES);
        return R.success(userRedisVO);
    }

    /**
     * 重置密码接口，获取用户邮箱验证码
     *
     * @return
     */
    @GetMapping("/rest/get-email-code")
    public R restGetEmailCode(String username, String email) {
        if (email == null || email.equals("") || !emailUtils.isValidEmail(email)) {
            return R.success(requestUtils.BAD_REQUEST_STATE, requestUtils.BAD_REQUEST_MESSAGE);
        }

        // 判断是否存在 redis key, 不存在则表示未开通权限
        if (!redisUtils.hasKey(RedisKeyUtils.getRestPasswordKey(username))) {
            return R.success(requestUtils.BAD_REQUEST_STATE, requestUtils.BAD_REQUEST_MESSAGE);
        }

        // 判断该邮箱是否绑定该用户名
        UserRedisVO userRedisVO = (UserRedisVO) redisUtils.get(RedisKeyUtils.getRestPasswordKey(username));
        if (!userRedisVO.getEmail().equals(email)) {
            return R.success(requestUtils.NO_PASS_COMMON_STATE, "该邮箱与账号:" + username + "绑定的邮箱不一致！");
        }

        // 判断是否存在验证码
        if (redisUtils.hasKey(email)) {
            return R.success(requestUtils.NO_PASS_COMMON_STATE, "验证码已发送, 请注意查看哦!");
        }

        User resultUser = new User();
        resultUser.setEmail(email);
        resultUser.setUsername(username);
        userService.generateRestPwdEmailCode(resultUser);
        return R.success("已发送验证码至" + email + "，请注意查收。");
    }


    @PostMapping("/rest/verify-email-code")
    public R verifyEmailCode(@RequestBody Map<String, String> data) {
        String email = data.get("email");
        String emailCode = data.get("emailCode");
        // todo: 验证码通过后，返回给用户一个 token 密钥，5 分钟内有效，拿着这个密钥就可以更改密码了，不用存入 redis
        if (email == null || emailCode == null) {
            return R.success(requestUtils.BAD_REQUEST_STATE, requestUtils.BAD_REQUEST_MESSAGE);
        }

        // 判断邮箱验证码是否正确
        if (!redisUtils.hasKey(RedisKeyUtils.getRestPasswordEmailKey(email))) {
            return R.success(requestUtils.AUTH_CODE_PASS_STATE, requestUtils.AUTH_CODE_PASS_MESSAGE);
        }
        String redisEmailCode = (String) redisUtils.get(RedisKeyUtils.getRestPasswordEmailKey(email));
        // 验证码错误
        if (!redisEmailCode.equals(emailCode)) {
            return R.success(requestUtils.AUTH_CODE_ERROR_STATE, requestUtils.AUTH_CODE_ERROR_MESSAGE);
        }

        // 验证码正确生成令牌
        Map<String, Object> map = new HashMap<>();
        map.put(email, emailCode);
        Object token = jwtUtils.generateToken(map, 5);
        return R.success(token);
    }

    /**
     * 重置密码接口，重新设置用户密码
     *
     * @return
     */
    @PostMapping("/rest/pwd")
    public R restPwd(@RequestBody ResetPasswordDTO resetPasswordDTO) {
        if (resetPasswordDTO.getUser().getUsername() == null || resetPasswordDTO.getUser().getEmail() == null) {
            return R.success(requestUtils.BAD_REQUEST_STATE, requestUtils.BAD_REQUEST_MESSAGE);
        }

        // 判断是否存在 redis key
        if (!redisUtils.hasKey(RedisKeyUtils.getRestPasswordKey(resetPasswordDTO.getUser().getUsername()))) {
            return R.success(requestUtils.NO_PASS_COMMON_STATE, "更改密码超时，请头开始！");
        }

        // 判断该邮箱是否绑定该用户名
        UserRedisVO userRedisVO = (UserRedisVO) redisUtils.get(RedisKeyUtils.getRestPasswordKey(resetPasswordDTO.getUser().getUsername()));
        if (!userRedisVO.getEmail().equals(resetPasswordDTO.getUser().getEmail())) {
            return R.success(requestUtils.NO_PASS_COMMON_STATE, "该用户未绑定该邮箱！");
        }

        // 判断用户手持修改密码的令牌是否有效
        boolean isPass = jwtUtils.validateToken(resetPasswordDTO.getKey());
        if (!isPass) {
            return R.success(requestUtils.NO_PASS_COMMON_STATE, "更改密码超时，请头开始！");
        }

        // 更新密码, 按照用户名
        userService.modifyPassword(resetPasswordDTO.getUser());
        // 删除当前登录的用户-这里不用删除，修改了密码登录拦截器会自动拦截的
        return R.success("更改密码成功!");
    }
}
